package com.hsqyz.esp32_led.controller;

import com.hsqyz.esp32_led.common.web.domain.R;
import com.hsqyz.esp32_led.model.dto.Esp32MessageDto;
import com.hsqyz.esp32_led.netty.cache.GlobalChannelCache;
import io.netty.channel.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * ESP32 LED控制控制器
 * 
 * 该控制器提供了与ESP32设备交互的REST API接口，包括：
 * 1. 获取已连接的设备列表
 * 2. 向指定设备发送控制命令
 * 
 * 使用Netty作为底层通信框架，通过GlobalChannelCache管理设备连接
 */
@Slf4j
@RestController
@RequestMapping("test")
@RequiredArgsConstructor
public class TestController {

    /**
     * 全局通道缓存，用于管理所有ESP32设备的连接
     * 提供了设备ID与Channel的映射关系管理
     */
    private final GlobalChannelCache channelCache;

    /**
     * 获取所有已连接的ESP32设备列表
     * 
     * @return 返回包含所有已连接设备ID的列表
     *         如果没有任何设备连接，则返回空列表
     */
    @RequestMapping("getDevices")
    public R<List<String>> getDevices() {
        // 从通道缓存中获取所有设备映射
        Map<String, Channel> devices = channelCache.getAllDevices();
        // 将设备ID列表转换为List并返回
        List<String> deviceIds = new ArrayList<>(devices.keySet());
        return R.ok(deviceIds);
    }

    /**
     * 向指定的ESP32设备发送控制命令
     * 
     * @param messageDto 包含以下信息的消息对象：
     *                   - clientId: 目标设备的唯一标识符
     *                   - cmd: 要执行的命令（如"on"或"off"）
     * @return 返回操作结果，成功时返回R.ok()
     *         如果设备未连接，会在日志中记录错误信息
     */
    @RequestMapping("sendMsg")
    public R<Esp32MessageDto> sendMsg(@RequestBody Esp32MessageDto messageDto) {
        // 从消息对象中获取目标设备ID
        String clientId = messageDto.getClientId();

        // 根据设备ID获取对应的Netty Channel
        Channel channel = channelCache.getChannelByClientId(clientId);

        // 检查Channel是否存在并发送消息
        if (channel != null) {
            // 将消息写入Channel并刷新，确保消息被发送
            channel.writeAndFlush(messageDto);
        } else {
            // 如果Channel不存在，说明设备未连接，记录错误日志
            log.error("设备：{}，无法找到对应的Channel，命令发送失败", clientId);
        }

        // 返回成功响应
        return R.ok();
    }
}
